package cn.hill4j.tool.core.wrap;

/**
  * ClassName: WarpHandler
  * Description: 包装执行器
  * @param <R> 包装执行器响应结果类型
  * @author hillchen
  * Date: 2023/7/31
  * @version: 1.0
  */
public class WrapHandler<R> {
    /**
     * 默认前置执行器
     */
    private static BeforeHandler DEF_BEFORE_HANDLER = () -> {};
    /**
     * 默认后置执行器
     */
    private static AfterHandler DEF_AFTER_HANDLER = r -> {};
    /**
     * 默认前置执行器
     */
    private static ExceptionHandler DEF_EXCEPTION_HANDLER = e -> e;
    /**
     * 默认finally执行器
     */
    private static FinallyHandler DEF_FINALLY_HANDLER = (r,e) -> {};

    /**
     * 业务执行器
     */
    private final Invoker<R> invoker;
    /**
     * 前置执行器
     */
    private BeforeHandler beforeHandler = DEF_BEFORE_HANDLER;
    /**
     * 后置执行器
     */
    private AfterHandler<R> afterHandler = DEF_AFTER_HANDLER;
    /**
     * 异常执行器
     */
    private ExceptionHandler exceptionHandler = DEF_EXCEPTION_HANDLER;
    /**
     * finally执行器
     */
    private FinallyHandler<R> finallyHandler = DEF_FINALLY_HANDLER;

    /**
     * @author hillchen
     * Description 构造方法
     * Date: 2023/8/7 23:02
     * @param invoker 具体需要执行的执行器，真实需要执行的业务逻辑
     * @return WarpHandler 包装执行器构造器
     **/
    private WrapHandler(Invoker<R> invoker) {
        this.invoker = invoker;
    }

    /**
     * @author hillchen
     * Description 执行器包装起来进行生成包装执行器构造器
     * Date: 2023/8/7 23:02
     * @param <R> 执行器响应结果类型
     * @param invoker 具体需要执行的执行器，真实需要执行的业务逻辑
     * @return WarpHandler 包装执行器构造器
     **/
    public static <R> WrapHandler<R> wrap(Invoker<R> invoker){
        return new WrapHandler<>(invoker);
    }
    /**
     * @author hillchen
     * Description 执行器包装起来进行生成包装执行器构造器
     * Date: 2023/8/7 23:05
     * @param runnable 具体需要执行的执行器，真实需要执行的业务逻辑
     * @return WarpHandler 包装执行器构造器
     **/
    public static WrapHandler<Boolean> wrap(Runnable  runnable){
        return new WrapHandler<Boolean>(() -> {runnable.run();return true;});
    }

    /**
     * @author hillchen
     * Description 包装执行业务逻辑，并抛出可捕获异常
     * Date: 2023/7/31 23:53
     * @return R
     * @throws Throwable 执行异常
     **/
    public R invoke() throws Throwable{
        R result = null;
        Throwable wrapExc = null;
        try {
            beforeHandler.invokeBefore();
            result = invoker.invoke();
            afterHandler.invokeAfter(result);
            return result;
        }catch (Throwable e){
            wrapExc = exceptionHandler.invokeException(e);
            throw wrapExc;
        }finally {
            finallyHandler.invokeFinally(result,wrapExc);
        }
    }

    /**
     * @author hillchen
     * Description 包装执行业务逻辑，并抛出Runtime异常
     * Date: 2023/7/31 23:54
     * @return R
     **/
    public R invokeNoThrow(){
        R result = null;
        Throwable wrapExc = null;
        try {
            beforeHandler.invokeBefore();
            result = invoker.invoke();
            afterHandler.invokeAfter(result);
            return result;
        }catch (Throwable e){
            wrapExc = exceptionHandler.invokeException(e);
            if(wrapExc instanceof RuntimeException){
                throw (RuntimeException)wrapExc;
            }else {
                throw new WrapRuntimeException(wrapExc.getMessage(),wrapExc);
            }
        }finally {
            finallyHandler.invokeFinally(result,wrapExc);
        }
    }

    /**
      * ClassName: BeforeHandler
      * Description: 包装执行器前置操作
      * @author hillchen
      * Date: 2023/7/31
      * @version: 1.0
      */
    public interface BeforeHandler{
        /**
         * @author hillchen
         * Description 执行前置方法
         * Date: 2023/7/31 23:16
     **/
        void invokeBefore();
    }
    /**
     * ClassName: AfterHandler
     * Description: 包装执行器后置操作
     * @param <R> 包装执行器响应结果类型
     * @author hillchen
     * Date: 2023/7/31
     * @version: 1.0
     */
    public interface AfterHandler<R>{
        /**
         * @author hillchen
         * Description //TODO
         * Date: 2023/7/31 23:27
         * @param result 处理结果
         **/
        void invokeAfter(R result);
    }
    /**
      * ClassName: ExceptionHandler
      * Description: 包装执行器异常操作
      * @author hillchen
      * Date: 2023/7/31
      * @version: 1.0
      */
    public interface ExceptionHandler{
        /**
         * @author hillchen
         * Description 包装执行器异常操作，将执行器的执行异常进行封装
         * Date: 2023/7/31 23:33
         * @param e 执行器异常信息
         **/
        Throwable invokeException(Throwable e);
    }
    /**
      * ClassName: FinallyHandler
      * Description: 包装执行器finally操作
     * @param <R> 包装执行器响应结果类型
      * @author hillchen
      * Date: 2023/7/31
      * @version: 1.0
      */
    public interface FinallyHandler<R>{
        /**
         * @author hillchen
         * Description 包装执行器finally操作
         * Date: 2023/7/31 23:34
         * @param result
         * @param e
         **/
        void invokeFinally(R result, Throwable e);
    }
    /**
     * ClassName: Invoker
     * Description: 目标执行器
     * @param <R> 包装执行器响应结果类型
     * @author hillchen
     * Date: 2023/7/31
     * @version: 1.0
     */
    public interface Invoker<R>{
        /**
         * @author hillchen
         * Description 执行业务操作
         * Date: 2023/7/31 23:34
         **/
        R invoke() throws Throwable;
    }


    /**
     * @author hillchen
     * Description 添加前置处理器
     * Date: 2023/8/7 23:05
     * @param beforeHandler 前置处理器
     * @return WarpHandler 包装执行器构造器
     **/
    public WrapHandler<R> before(BeforeHandler beforeHandler){
        this.beforeHandler = beforeHandler;
        return this;
    }
    /**
     * @author hillchen
     * Description 添加后置处理器
     * Date: 2023/8/7 23:06
     * @param afterHandler 后置处理器
     * @return WarpHandler 包装执行器构造器
     **/
    public WrapHandler<R> after(AfterHandler afterHandler){
        this.afterHandler = afterHandler;
        return this;
    }
    /**
     * @author hillchen
     * Description 添加异常执行器
     * Date: 2023/8/7 23:06
     * @param exceptionHandler 异常执行器
     * @return WarpHandler 包装执行器构造器
     **/
    public WrapHandler<R> except(ExceptionHandler exceptionHandler){
        this.exceptionHandler = exceptionHandler;
        return this;
    }
    /**
     * @author hillchen
     * Description 添加finally执行器
     * Date: 2023/8/7 23:07
     * @param finallyHandler finally执行器
     * @return WarpHandler 包装执行器构造器
     **/
    public WrapHandler<R> fin(FinallyHandler<R> finallyHandler){
        this.finallyHandler = finallyHandler;
        return this;
    }
}
